#define __PIC24F04KA200__
#include "p24F04KA200.h"
#include "../common/uart.h"
#include "adc.h"
#include "rf.h"
#include "tc77.h"
#include "system.h"
#include "util.h"
#include "../common/protocol.h"
#include <stdio.h>

#define _ISR __attribute__((interrupt))

#define N_VIRTUAL_TIMERS 3

void t4();
void t5();
void t6();

unsigned timers[] = {0, 0, 0};
unsigned timer_period[] = {1, 10, 1};
void (*timer_functions[])() = {t4, t5, t6};

char buf[10];
void send_im_alive();
unsigned char message_seq_num = 0;

int main() {
    unsigned i, j, k = 0;
    unsigned char c = 0;

    CLKDIVbits.RCDIV = 0b101;
    //OSCTUNbits.TUN = 5;

    LED_TRIS = TX_TRIS = TC77_PWR_TRIS = 0;
    LED = 0;
    TC77_PWR = 0;

    adc_init();
    rf_init();
    uart_init(BAUD_RATE_1200,
            UART_BRGH_ENABLE,
            UART_RXINV_ENABLE,
            UART_UTXINV_ENABLE);
    tc77_init();


/*
            rf_on();
            while (1) {
                write('U');
            }
*/
    /*
        rf_on();
        while (1) {
            for (i = 0; i < 256; i++) {
                write(0x55);
            }
        }
     */
    /*
            rf_on();
            OSCTUNbits.TUN -= 5;
            while (1) {

                        OSCTUNbits.TUN++;
                        j = OSCTUN;
                        for (i = 0; i < 10; i++) {
                            writeStrUnsLn("OSC=", j);
                        }


                if (++U1BRG == 26) U1BRG = 23;
                for (i = 0; i < 10; i++) {
                    writeStrUnsLn("U1BRG=", U1BRG);
                }
                write('#');
                for (j = 0; j < 4; j++)
                    for (i = 0; i < 255; i++)
                        write('U');
            }
            rf_off();
     */


    /*
        rf_on();
        while (1) {
            if (++U1BRG == 26) U1BRG = 23;
            for (i = 0; i < 10; i++) {
                writeStrUnsLn("U1BRG=", U1BRG);
            }
            write('#');
            for (j = 0; j < 4; j++)
                for (i = 0; i < 255; i++)
                    write('U');
        }
        rf_off();
     */

    IFS0bits.T1IF = 0;
    IEC0bits.T1IE = 1;

    PR1 = 0xFF;

    T1CONbits.TCS = 0;
    T1CONbits.TCKPS0 = 1;
    T1CONbits.TCKPS1 = 1;
    T1CONbits.TGATE = 0;
    T1CONbits.TSIDL = 0;
    /*

        rf_on();

        while (1) {
            writeStrManchester("A wiki is a website that allows the easy creation and editing of any number of interlinked web pages via a web browser using a simplified markup language or ...\r\n");
        }
     */

    rf_on();

    writeStr("\r\nSensor ");
    writeStr(itoa(ID, buf));
    writeStr(" is alive\r\n");

    LED = 1;
    /*
        while (1)
            write('U');
     */

    /*
        while (1) {
            for (i = 22; i < 29; i++) {
                writeStr("UUUUUUUUUUUUUUUUUUU\r\n");
                for (j = 0; j < 50; j++) {
                    U1BRG = i;
                    writeStr(itoa(i, buf));
                    writeStr("\r\n");
                }
            }
        }
     */


    rf_off();

    rf_on();
    send_im_alive();
    rf_off();

    for (i = 0; i < 12; i++) {
        LED = 1;
        for (j = 0; j < 1000; j++);
        LED = 0;
        for (j = 0; j < 1000; j++);
    }

    T1CONbits.TON = 1;

/*
    while (1) {
        write('U');
    }
*/
    
    while (1)
        Idle();

    while (1) {
        for (i = 0; i < 1; i++)
            for (j = 0; j < 50000; j++);

        /*
                writeStr("UUUUU\n\r");
         */
        LED = 1;
        rf_on();
        writeStr("\r\nSensor ");
        writeStr(itoa(ID, buf));
        writeStr(" is alive\r\n");

        send_im_alive();

        rf_off();
        LED = 0;
    }
}

void send_im_alive() {
    unsigned char checksum = 0;
    unsigned int count = 0;
    checksum = 0;
    checksum += MESG_TYPE_NODE_ALIVE;
    checksum += message_seq_num;
    checksum += 2;
    checksum += BOARD_TYPE_SIMPLE_NODE_V5;
    checksum += ID;

    for (count = 0; count < N_RETRY; count++) {
        pWrite(START_BYTE);
        pWrite(MESG_TYPE_NODE_ALIVE);
        pWrite(message_seq_num);
        pWrite(2);
        pWrite(BOARD_TYPE_SIMPLE_NODE_V5);
        pWrite(ID);
        pWrite(checksum);

        write(0);
    }

    message_seq_num++;
}

void send_pir_detection() {
    unsigned char checksum = 0;
    unsigned int count = 0;
    checksum += MESG_TYPE_PIR_DETECTION;
    checksum += message_seq_num;
    checksum += 1;
    checksum += ID;

    for (count = 0; count < N_RETRY; count++) {
        pWrite(START_BYTE);
        pWrite(MESG_TYPE_PIR_DETECTION);
        pWrite(message_seq_num);
        pWrite(1);
        pWrite(ID);
        pWrite(checksum);

        write(0);
    }

    message_seq_num++;
}

void _ISR _T1Interrupt(void) {
    unsigned i = 0;
    IFS0bits.T1IF = 0;

    for (i = 0; i < N_VIRTUAL_TIMERS; i++) {
        timers[i]++;
        if (timers[i] == timer_period[i]) {
            timer_functions[i]();
            timers[i] = 0;
        }
    }
}

void t4() {
    static unsigned lastValue;
    static unsigned recentDetection = 0;
    static unsigned diff = 0;
    unsigned value;

    value = adc_convert(PIR_SENSOR_AN);
    diff = uns_abs_diff(lastValue, value);

    timer_period[1] = 10 + (diff | 0b111);

    rf_on();
    writeStrUnsLn("UUUUUUUUU PIR=", value);

    if (0 &&
            diff >
            (recentDetection ? PIR_STABILITY_THRESHOLD : PIR_DETECTION_THRESHOLD)) {
        if (!recentDetection || !PIR_WAIT_TO_STABILIZE) {
            recentDetection = 1;

            LED = 1;
            rf_on();

            /*
                        writeStr("U PIR ");
                        writeStr(itoa(ID, buf));
                        writeStr(" DETECTION (");
                        writeStr(itoa(uns_abs_diff(lastValue, value), buf));
                        writeStr(")\r\n");
             */

            /*
                        send_pir_detection();
             */

            rf_off();
        }
    } else {
        recentDetection = 0;
        LED = 0;
    }

    lastValue = value;
}

void t5() {
    /*
        LED = 1;
     */
    rf_on();
    send_im_alive();
    rf_off();
    /*
        LED = 0;
     */
}

void t6() {
}
